#include "DependencyEncoder3OGSibling.h"
#include "math.h"
#include "ObjectReader.h"
#include "DependencyInstance.h"
#include <ctime>

DependencyEncoder3OGSibling::DependencyEncoder3OGSibling(int maxLength, DependencyPipe *pipe, char *trainforest, Parameters *param) : DependencyEncoder2O(maxLength, pipe, trainforest, param){
	probs_gtrips = vector<vector<vector<vector<double> > > >(maxLength);
	for(int i = 0; i < maxLength; i++){
		probs_gtrips[i] = vector<vector<vector<double> > >(maxLength);
		for(int j = 0; j < maxLength; j++){
			int nn1;
			if(j == i){
				nn1 = 0;
			}
			else if(j < i){
				nn1 = i;
			}
			else{
				nn1 = maxLength - i - 1;
			}
			probs_gtrips[i][j] = vector<vector<double> >(nn1);
			for(int k = 0; k < nn1; k++){
				int nn2;
				if(j < i){
					if(k < j){
						nn2 = k;
					}
					else if(k == j){
						nn2 = i;
					}
					else{
						nn2 = i - k - 1;
					}
					probs_gtrips[i][j][k] = vector<double>(nn2);
				}
				else{
					int kk = k + i + 1;
					if(kk < j){
						nn2 = k;
					}
					else if(kk == j){
						nn2 = maxLength - i - 1;
					}
					else{
						nn2 = maxLength - kk - 1;
					}
					probs_gtrips[i][j][k] = vector<double>(nn2);
				}
			}
		}
	}

	probs_gsibs = vector<vector<vector<vector<double> > > >(maxLength);
	probs_coords = vector<vector<vector<double> > >(maxLength);
	for(int i = 0; i < maxLength; i++){
		probs_gsibs[i] = vector<vector<vector<double> > >(maxLength);
		probs_coords[i] = vector<vector<double> >(maxLength);
		for(int j = 0; j < maxLength; j++){
			int nn;
			if(i == j){
				nn = 0;
			}
			else if(j < i){
				nn = i;
			}
			else{
				nn = maxLength;
			}
			probs_gsibs[i][j] = vector<vector<double> >(nn);
			probs_coords[i][j] = vector<double>(nn);
			for(int k = 0; k < nn; k++){
				if(i < j){
					if(k > i){
						probs_gsibs[i][j][k] = vector<double>(2);
					}
					else{
						probs_gsibs[i][j][k] = vector<double>(0);
					}
				}
				else{
					probs_gsibs[i][j][k] = vector<double>(2);
				}
			}
		}
	}
}

DependencyEncoder3OGSibling::~DependencyEncoder3OGSibling(){}

int DependencyEncoder3OGSibling::getKey(int g, int s, int t, int dir, int comp, int length){
	int key = g;
	key = key * length + s;
	key = key * length + t;
	key = key * 2 + dir;
	key = key * 3 + comp;
	return key;
}

double DependencyEncoder3OGSibling::getGrandTripProb(int gpar, int par, int ch1, int ch2, std::vector<vector<vector<vector<double> > > > &probs_gtrips){
	int ch1_fin, ch2_fin;
	if(gpar > par){
		ch1_fin = ch1;
		if(ch1 > par){
			ch2_fin = ch2 - ch1 - 1;
		}
		else{
			ch2_fin = ch2;
		}
	}
	else{
		ch1_fin = ch1 - gpar - 1;
		if(ch1 > par){
			ch2_fin = ch2 - ch1 - 1;
		}
		else{
			ch2_fin = ch2 - gpar - 1;
		}
	}
	return probs_gtrips[gpar][par][ch1_fin][ch2_fin];
}

double DependencyEncoder3OGSibling::getZ(int length, double *beta, DependencyInstance *instance){
	//pipe
	DependencyPipe3OGSibling *pipe_gs = (DependencyPipe3OGSibling*)(pipe);

	int key, key1, key2;
	for(int s = 0; s < length; s++){
		for(int g = 0; g < length; g++){
			key = getKey(g, s, s, 0, 1, length);
			beta[key] = 0.0;
			key = getKey(g, s, s, 1, 1, length);
			beta[key] = 0.0;
		}
	}

	for(int j = 1; j < length; j++){
		for(int s = 0; s < length && s + j < length; s++){
			int t = s + j;

			double prodProb_st = probs[s][t][0];
			double prodProb_ts = probs[s][t][1];

			for(int g = 0; g < length; g++){
				if(g >= s && g <= t){
					continue;
				}

				//init beta
				//incomplete spans
				//r == s
				int key_gst_0 = getKey(g, s, t, 0, 0, length);
				double prodProb_gsst = getGrandTripProb(g, s, s, t, probs_gtrips) + probs_gsibs[g][s][t][0];
				prodProb_gsst += probs_trips[s][s][t] + probs_sibs[s][t][0] + probs_grands[g][s][t] + probs_gchs[g][t] + prodProb_st;
				key1 = getKey(g, s, s, 0, 1, length);
				key2 = getKey(s, s + 1, t, 1, 1, length);
				beta[key_gst_0] = logsumexp(beta[key_gst_0], beta[key1] + beta[key2] + prodProb_gsst, true);

				//r == t
				int key_gts_0 = getKey(g, s, t, 1, 0, length);
				double prodProb_gtts = getGrandTripProb(g, t, t, s, probs_gtrips) + probs_gsibs[g][t][s][0];
				prodProb_gtts += probs_trips[t][t][s] + probs_sibs[t][s][0] + probs_grands[g][t][s] + probs_gchs[g][s] + prodProb_ts;
				key1 = getKey(t, s, t - 1, 0, 1, length);
				key2 = getKey(g, t, t, 1, 1, length);
				beta[key_gts_0] = logsumexp(beta[key_gts_0], beta[key1] + beta[key2] + prodProb_gtts, true);

				//sibling spans
				int key_gst_2 = getKey(g, s, t, 0, 2, length);
				beta[key_gst_2] = 0.0;
				int key_gts_2 = getKey(g, s, t, 1, 2, length);
				beta[key_gts_2] = 0.0;
				bool flg_gst_2 = true, flg_gts_2 = true;

				//complete spans
				int key_gst_1 = getKey(g, s, t, 0, 1, length);
				beta[key_gst_1] = 0.0;
				int key_gts_1 = getKey(g, s, t, 1, 1, length);
				beta[key_gts_1] = 0.0;
				bool flg_gst_1 = true, flg_gts_1 = true;

				//calc sibling spans
				for(int r = s; r < t; r++){
					key1 = getKey(g, s, r, 0, 1, length);
					key2 = getKey(g, r + 1, t, 1, 1, length);
					beta[key_gst_2] = logsumexp(beta[key_gst_2], beta[key1] + beta[key2], flg_gst_2);
					flg_gst_2 = false;

					beta[key_gts_2] = logsumexp(beta[key_gts_2], beta[key1] + beta[key2], flg_gts_2);
					flg_gts_2 = false;
				}

				//calc incomplete spans
				for(int r = s + 1; r < t; r++){
					// s -> (r,t)
					key1 = getKey(g, s, r, 0, 0, length);
					key2 = getKey(s, r, t, 0, 2, length);
					double prodProb_gsrt = getGrandTripProb(g, s, r, t, probs_gtrips) + probs_gsibs[g][r][t][1];
					bool coord = pipe_gs->isCoord(instance, s, r);
					if(coord){
						prodProb_gsrt += probs_coords[g][s][t];
					}
					prodProb_gsrt += probs_trips[s][r][t] + probs_sibs[r][t][1] + probs_grands[g][s][t] + probs_gchs[g][t] + prodProb_st;
					beta[key_gst_0] = logsumexp(beta[key_gst_0], beta[key1] + beta[key2] + prodProb_gsrt, false);

					// t -> (r,s)
					key1 = getKey(t, s, r, 1, 2, length);
					key2 = getKey(g, r, t, 1, 0, length);
					double prodProb_gtrs = getGrandTripProb(g, t, r, s, probs_gtrips) + probs_gsibs[g][r][s][1];
					coord = pipe_gs->isCoord(instance, t, r);
					if(coord){
						prodProb_gtrs += probs_coords[g][t][s];
					}
					prodProb_gtrs += probs_trips[t][r][s] + probs_sibs[r][s][1] + probs_grands[g][t][s] + probs_gchs[g][s] + prodProb_ts;
					beta[key_gts_0] = logsumexp(beta[key_gts_0], beta[key1] + beta[key2] + prodProb_gtrs, false);
				}

				//calc complete spans
				for(int r = s; r <= t; r++){
					if(r != s){
						key1 = getKey(g, s, r, 0, 0, length);
						key2 = getKey(s, r, t, 0, 1, length);
						beta[key_gst_1] = logsumexp(beta[key_gst_1], beta[key1] + beta[key2], flg_gst_1);
						flg_gst_1 = false;
					}
					if(r != t){
						key1 = getKey(t, s, r, 1, 1, length);
						key2 = getKey(g, r, t, 1, 0, length);
						beta[key_gts_1] = logsumexp(beta[key_gts_1], beta[key1] + beta[key2], flg_gts_1);
						flg_gts_1 = false;
					}
				}
			}
		}
	}

	int end = length - 1;

	for(int j = 1; j < length; j++){
		int t = j, s = end - j;
		//init
		key = getKey(0, 0, t, 0, 0, length);
		double prodProb_00t = probs_trips[0][0][t] + probs_sibs[0][t][0] + probs[0][t][0];
		key1 = getKey(0, 1, t, 1, 1, length);
		beta[key] = logsumexp(beta[key], beta[key1] + prodProb_00t, true);

		for(int r = 1; r < t; r++){
			double prodProb_0rt = probs_trips[0][r][t] + probs_sibs[r][t][1] + probs[0][t][0];
			key1 = getKey(0, 0, r, 0, 0, length);
			key2 = getKey(0, r, t, 0, 2, length);
			beta[key] = logsumexp(beta[key], beta[key1] + beta[key2] + prodProb_0rt, false);
		}

		//init
		key = getKey(s, s, end, 1, 0, length);
		double prodProb_nns = probs_trips[end][end][s] + probs_sibs[end][s][0] + probs[s][end][1];
		key1 = getKey(end, s, end - 1, 0, 1, length);
		beta[key] = logsumexp(beta[key], beta[key1] + prodProb_nns, true);

		for(int r = s + 1; r < end; r++){
			double prodProb_nrs = probs_trips[end][r][s] + probs_sibs[r][s][1] + probs[s][end][1];
			key1 = getKey(end, s, r, 0, 2, length);
			key2 = getKey(r, r, end, 1, 0, length);
			beta[key] = logsumexp(beta[key], beta[key1] + beta[key2] + prodProb_nrs, false);
		}
	}
	int key_0n_1 = getKey(0, 0, end, 0, 1, length);
	int key_n0_1 = getKey(0, 0, end, 1, 1, length);
	bool flg_0n_1 = true, flg_n0_1 = true;
	for(int r = 0; r < length; r++){
		if(r != 0){
			key1 = getKey(0, 0, r, 0, 0, length);
			key2 = getKey(0, r, end, 0, 1, length);
			beta[key_0n_1] = logsumexp(beta[key_0n_1], beta[key1] + beta[key2], flg_0n_1);
			flg_0n_1 = false;
		}
		if(r != end){
			key1 = getKey(end, 0, r, 1, 1, length);
			key2 = getKey(r, r, end, 1, 0, length);
			beta[key_n0_1] = logsumexp(beta[key_n0_1], beta[key1] + beta[key2], flg_n0_1);
			flg_n0_1 = false;
		}
	}
	return logsumexp(beta[key_0n_1], beta[key_n0_1], false);
}

void DependencyEncoder3OGSibling::inside_outside(int length, double *beta, double *alpha, DependencyInstance *instance){
	int end = length - 1;
	int key;
	for(int c = 0; c < 3; c++){
		key = getKey(0, 0, end, 0, c, length);
		alpha[key] = 0.0;
		key = getKey(0, 0, end, 1, c, length);
		alpha[key] = 0.0;
	}

	DependencyPipe3OGSibling *pipe_gs = (DependencyPipe3OGSibling*)(pipe);

	for(int j = end; j >= 1; j--){
		int t = j, s = end - j;

		//init
		int key_t = getKey(0, 0, t, 0, 0, length);
		int key_b = getKey(0, t, end, 0, 1, length);
		int key_a = getKey(0, 0, end, 0, 1, length);
		alpha[key_t] = logsumexp(alpha[key_t], beta[key_b] + alpha[key_a], true);

		for(int r = t + 1; r < length; r++){
			double prodProb_0tr = probs_trips[0][t][r] + probs_sibs[t][r][1] + probs[0][r][0];
			key_b = getKey(0, t, r, 0, 2, length);
			key_a = getKey(0, 0, r, 0, 0, length);
			alpha[key_t] = logsumexp(alpha[key_t], beta[key_b] + alpha[key_a] + prodProb_0tr, false);
		}

		//init
		int key_s = getKey(s, s, end, 1, 0, length);
		key_b = getKey(end, 0, s, 1, 1, length);
		key_a = getKey(0, 0, end, 1, 1, length);
		alpha[key_s] = logsumexp(alpha[key_s], beta[key_b] + alpha[key_a], true);

		for(int r = 0; r < s; r++){
			double prodProb_nsr = probs_trips[end][s][r] + probs_sibs[s][r][1] + probs[r][end][1];
			key_b = getKey(end, r, s, 0, 2, length);
			key_a = getKey(r, r, end, 1, 0, length);
			alpha[key_s] = logsumexp(alpha[key_s], beta[key_b] + alpha[key_a] + prodProb_nsr, false);
		}
	}

	for(int j = end; j >= 1; j--){
		for(int s = 0; s + j < length; s++){
			int t = s + j;
			int key_a, key_b;
			bool coord;

			for(int g = 0; g < s; g++){
				//sibling spans
				int key_gst_2 = getKey(g, s, t, 0, 2, length);
				alpha[key_gst_2] = 0.0;
				bool flg_gst_2 = true;
				for(int r = 0; r < length; r++){
					if(r >= g && r <= t){
						continue;
					}
					double prodProb_rgst = getGrandTripProb(r, g, s, t, probs_gtrips) + probs_gsibs[r][s][t][1];
					coord = pipe_gs->isCoord(instance, g, s);
					if(coord){
						prodProb_rgst += probs_coords[r][g][t];
					}
					prodProb_rgst += probs_trips[g][s][t] + probs_sibs[s][t][1] + probs_grands[r][g][t] + probs_gchs[r][t] + probs[g][t][0];
					key_b = getKey(r, g, s, 0, 0, length);
					key_a = getKey(r, g, t, 0, 0, length);
					alpha[key_gst_2] = logsumexp(alpha[key_gst_2], beta[key_b] + alpha[key_a] + prodProb_rgst, flg_gst_2);
					flg_gst_2 = false;
				}
				if(g == 0){
					double prodProb_0st = probs_trips[0][s][t] + probs_sibs[s][t][1] + probs[0][t][0];
					key_b = getKey(0, 0, s, 0, 0, length);
					key_a = getKey(0, 0, t, 0, 0, length);
					alpha[key_gst_2] = logsumexp(alpha[key_gst_2], beta[key_b] + alpha[key_a] + prodProb_0st, flg_gst_2);
					flg_gst_2 = false;
				}

				//completed spans
				int key_gst_1 = getKey(g, s, t, 0, 1, length);
				alpha[key_gst_1] = 0.0;
				int key_gts_1 = getKey(g, s, t, 1, 1, length);
				alpha[key_gts_1] = 0.0;

				bool flg_gst_1 = true, flg_gts_1 = true;

				for(int r = 0; r < length; r++){
					if(r > t && r < length){
						key_b = getKey(g, t + 1, r, 1, 1, length);
						key_a = getKey(g, s, r, 0, 2, length);
						alpha[key_gst_1] = logsumexp(alpha[key_gst_1], beta[key_b] + alpha[key_a], flg_gst_1);
						flg_gst_1 = false;
					}
					if(r > g && r < s){
						key_b = getKey(g, r, s - 1, 0, 1, length);
						key_a = getKey(g, r, t, 0, 2, length);
						alpha[key_gts_1] = logsumexp(alpha[key_gts_1], beta[key_b] + alpha[key_a], flg_gts_1);
						flg_gts_1 = false;
					}
					if(r < g || r > t){
						key_b = getKey(r, g, s, 0, 0, length);
						key_a = getKey(r, g, t, 0, 1, length);
						alpha[key_gst_1] = logsumexp(alpha[key_gst_1], beta[key_b] + alpha[key_a], flg_gst_1);
						flg_gst_1 = false;

						if(g == s - 1){
							double prodProb_rggt = getGrandTripProb(r, g, g, t, probs_gtrips) + probs_gsibs[r][g][t][0];
							prodProb_rggt += probs_trips[g][g][t] + probs_sibs[g][t][0] + probs_grands[r][g][t] + probs_gchs[r][t] + probs[g][t][0];
							key_a = getKey(r, g, t, 0, 0, length);
							alpha[key_gts_1] = logsumexp(alpha[key_gts_1], alpha[key_a] + prodProb_rggt, flg_gts_1);
							flg_gts_1 = false;
						}
					}
				}
				if(g == 0 && t == end){
					key_b = getKey(0, 0, s, 0, 0, length);
					key_a = getKey(0, 0, end, 0, 1, length);
					alpha[key_gst_1] = logsumexp(alpha[key_gst_1], beta[key_b] + alpha[key_a], flg_gst_1);
					flg_gst_1 = false;
				}
				if(g == 0 && s == 1){
					double prodProb_00t = probs_trips[0][0][t] + probs_sibs[0][t][0] + probs[0][t][0];
					key_a = getKey(0, 0, t, 0, 0, length);
					alpha[key_gts_1] = logsumexp(alpha[key_gts_1], alpha[key_a] + prodProb_00t, flg_gts_1);
					flg_gts_1 = false;
				}
				//incompleted spans
				int key_gst_0 = getKey(g, s, t, 0, 0, length);
				alpha[key_gst_0] = 0.0;
				int key_gts_0 = getKey(g, s, t, 1, 0, length);
				alpha[key_gts_0] = 0.0;

				bool flg_gst_0 = true, flg_gts_0 = true;

				for(int r = t; r < length; r++){
					if(r != t){
						double prodProb_gstr = getGrandTripProb(g, s, t, r, probs_gtrips) + probs_gsibs[g][t][r][1];
						coord = pipe_gs->isCoord(instance, s, t);
						if(coord){
							prodProb_gstr += probs_coords[g][s][r];
						}
						prodProb_gstr += probs_trips[s][t][r] + probs_sibs[t][r][1] + probs_grands[g][s][r] + probs_gchs[g][r] + probs[s][r][0];
						key_b = getKey(s, t, r, 0, 2, length);
						key_a = getKey(g, s, r, 0, 0, length);
						alpha[key_gst_0] = logsumexp(alpha[key_gst_0], beta[key_b] + alpha[key_a] + prodProb_gstr, flg_gst_0);
						flg_gst_0 = false;
					}
					key_b = getKey(s, t, r, 0, 1, length);
					key_a = getKey(g, s, r, 0, 1, length);
					alpha[key_gst_0] = logsumexp(alpha[key_gst_0], beta[key_b] + alpha[key_a], flg_gst_0);
					flg_gst_0 = false;
				}
				for(int r = g + 1; r <= s; r++){
					if(r != s){
						double prodProb_gtsr = getGrandTripProb(g, t, s, r, probs_gtrips) + probs_gsibs[g][s][r][1];
						coord = pipe_gs->isCoord(instance, t, s);
						if(coord){
							prodProb_gtsr += probs_coords[g][t][r];
						}
						prodProb_gtsr += probs_trips[t][s][r] + probs_sibs[s][r][1] + probs_grands[g][t][r] + probs_gchs[g][r] + probs[r][t][1];
						key_b = getKey(t, r, s, 0, 2, length);
						key_a = getKey(g, r, t, 1, 0, length);
						alpha[key_gts_0] = logsumexp(alpha[key_gts_0], beta[key_b] + alpha[key_a] + prodProb_gtsr, flg_gts_0);
						flg_gts_0 = false;
					}
					key_b = getKey(t, r, s, 1, 1, length);
					key_a = getKey(g, r, t, 1, 1, length);
					alpha[key_gts_0] = logsumexp(alpha[key_gts_0], beta[key_b] + alpha[key_a], flg_gts_0);
					flg_gts_0 = false;
				}
			}
			for(int g = t + 1; g < length; g++){
				//sibling spans
				int key_gst_2 = getKey(g, s, t, 0, 2, length);
				alpha[key_gst_2] = 0.0;
				bool flg_gst_2 = true;
				for(int r = 0; r < length; r++){
					if(r >= s && r <= g){
						continue;
					}
					double prodProb_rgts = getGrandTripProb(r, g, t, s, probs_gtrips) + probs_gsibs[r][t][s][1];
					coord = pipe_gs->isCoord(instance, g, t);
					if(coord){
						prodProb_rgts += probs_coords[r][g][s];
					}
					prodProb_rgts += probs_trips[g][t][s] + probs_sibs[t][s][1] + probs_grands[r][g][s] + probs_gchs[r][s] + probs[s][g][1];
					key_b = getKey(r, t, g, 1, 0, length);
					key_a = getKey(r, s, g, 1, 0, length);
					alpha[key_gst_2] = logsumexp(alpha[key_gst_2], beta[key_b] + alpha[key_a] + prodProb_rgts, flg_gst_2);
					flg_gst_2 = false;
				}
				if(g == end){
					double prodProb_nts = probs_trips[end][t][s] + probs_sibs[t][s][1] + probs[s][end][1];
					key_b = getKey(t, t, end, 1, 0, length);
					key_a = getKey(s, s, end, 1, 0, length);
					alpha[key_gst_2] = logsumexp(alpha[key_gst_2], beta[key_b] + alpha[key_a] + prodProb_nts, flg_gst_2);
					flg_gst_2 = false;
				}
				//completed spans
				int key_gst_1 = getKey(g, s, t, 0, 1, length);
				alpha[key_gst_1] = 0.0;
				int key_gts_1 = getKey(g, s, t, 1, 1, length);
				alpha[key_gts_1] = 0.0;

				bool flg_gst_1 = true, flg_gts_1 = true;

				for(int r = 0; r < length; r++){
					if(r > t && r < g){
						key_b = getKey(g, t + 1, r, 1, 1, length);
						key_a = getKey(g, s, r, 0, 2, length);
						alpha[key_gst_1] = logsumexp(alpha[key_gst_1], beta[key_b] + alpha[key_a], flg_gst_1);
						flg_gst_1 = false;
					}
					if(r >= 0 && r < s){
						key_b = getKey(g, r, s - 1, 0, 1, length);
						key_a = getKey(g, r, t, 0, 2, length);
						alpha[key_gts_1] = logsumexp(alpha[key_gts_1], beta[key_b] + alpha[key_a], flg_gts_1);
						flg_gts_1 = false;
					}
					if(r < s || r > g){
						if(g == t + 1){
							double prodProb_rggs = getGrandTripProb(r, g, g, s, probs_gtrips) + probs_gsibs[r][g][s][0];
							prodProb_rggs += probs_trips[g][g][s] + probs_sibs[g][s][0] + probs_grands[r][g][s] + probs_gchs[r][s] + probs[s][g][1];
							key_a = getKey(r, s, g, 1, 0, length);
							alpha[key_gst_1] = logsumexp(alpha[key_gst_1], alpha[key_a] + prodProb_rggs, flg_gst_1);
							flg_gst_1 = false;
						}

						key_b = getKey(r, t, g, 1, 0, length);
						key_a = getKey(r, s, g, 1, 1, length);
						alpha[key_gts_1] = logsumexp(alpha[key_gts_1], beta[key_b] + alpha[key_a], flg_gts_1);
						flg_gts_1 = false;
					}
				}

				if(g == end && t == end - 1){
					double prodProb_nns = probs_trips[end][end][s] + probs_sibs[end][s][0] + probs[s][end][1];
					key_a = getKey(s, s, end, 1, 0, length);
					alpha[key_gst_1] = logsumexp(alpha[key_gst_1], alpha[key_a] + prodProb_nns, flg_gst_1);
					flg_gst_1 = false;
				}
				if(g == end && s == 0){
					key_b = getKey(t, t, end, 1, 0, length);
					key_a = getKey(0, 0, end, 1, 1, length);
					alpha[key_gts_1] = logsumexp(alpha[key_gts_1], beta[key_b] + alpha[key_a], flg_gts_1);
					flg_gts_1 = false;
				}

				//incompleted spans
				int key_gst_0 = getKey(g, s, t, 0, 0, length);
				alpha[key_gst_0] = 0.0;
				int key_gts_0 = getKey(g, s, t, 1, 0, length);
				alpha[key_gts_0] = 0.0;

				bool flg_gst_0 = true, flg_gts_0 = true;

				for(int r = t; r < g; r++){
					if(r != t){
						double prodProb_gstr = getGrandTripProb(g, s, t, r, probs_gtrips) + probs_gsibs[g][t][r][1];
						coord = pipe_gs->isCoord(instance, s, t);
						if(coord){
							prodProb_gstr += probs_coords[g][s][r];
						}
						prodProb_gstr += probs_trips[s][t][r] + probs_sibs[t][r][1] + probs_grands[g][s][r] + probs_gchs[g][r] + probs[s][r][0];
						key_b = getKey(s, t, r, 0, 2, length);
						key_a = getKey(g, s, r, 0, 0, length);
						alpha[key_gst_0] = logsumexp(alpha[key_gst_0], beta[key_b] + alpha[key_a] + prodProb_gstr, flg_gst_0);
						flg_gst_0 = false;
					}
					key_b = getKey(s, t, r, 0, 1, length);
					key_a = getKey(g, s, r, 0, 1, length);
					alpha[key_gst_0] = logsumexp(alpha[key_gst_0], beta[key_b] + alpha[key_a], flg_gst_0);
					flg_gst_0 = false;
				}
				for(int r = 0; r <= s; r++){
					if(r != s){
						double prodProb_gtsr = getGrandTripProb(g, t, s, r, probs_gtrips) + probs_gsibs[g][s][r][1];
						coord = pipe_gs->isCoord(instance, t, s);
						if(coord){
							prodProb_gtsr += probs_coords[g][t][r];
						}
						prodProb_gtsr += probs_trips[t][s][r] + probs_sibs[s][r][1] + probs_grands[g][t][r] + probs_gchs[g][r] + probs[r][t][1];
						key_b = getKey(t, r, s, 0, 2, length);
						key_a = getKey(g, r, t, 1, 0, length);
						alpha[key_gts_0] = logsumexp(alpha[key_gts_0], beta[key_b] + alpha[key_a] + prodProb_gtsr, flg_gts_0);
						flg_gts_0 = false;
					}
					key_b = getKey(t, r, s, 1, 1, length);
					key_a = getKey(g, r, t, 1, 1, length);
					alpha[key_gts_0] = logsumexp(alpha[key_gts_0], beta[key_b] + alpha[key_a], flg_gts_0);
					flg_gts_0 = false;
				}
			}
		}
	}
}

void DependencyEncoder3OGSibling::getExpected(long double *expected, double *beta, double *alpha, double z, int length, DependencyInstance *instance){
	// Get production crap.
	int end = length - 1;
	bool coord;
	DependencyPipe3OGSibling *pipe_gs = (DependencyPipe3OGSibling*)(pipe);
	for (int w1 = 0; w1 < length; w1++) {
		for (int w2 = w1 + 1; w2 < length; w2++) {
			for (int ph = 0; ph < 2; ph++) {
				int *keys = NULL;
				int size = in->readArray(keys);
				double m = 0.0;
				int key_a, key_b1, key_b2;
				for(int g = 0; g < length; g++){
					if(g >= w1 && g <= w2){
						continue;
					}
					if(ph == 0){
						//m(g, s, -, t)
						//w1 = s, w2 = t
						double prodProb_gsst = getGrandTripProb(g, w1, w1, w2, probs_gtrips) + probs_gsibs[g][w1][w2][0];
						prodProb_gsst += probs_trips[w1][w1][w2] + probs_sibs[w1][w2][0] + probs_grands[g][w1][w2] + probs_gchs[g][w2] + probs[w1][w2][0];
						key_a = getKey(g, w1, w2, 0, 0, length);
						key_b1 = getKey(w1, w1 + 1, w2, 1, 1, length);
						m += exp(beta[key_b1] + alpha[key_a] + prodProb_gsst - z);

						for(int r = w1 + 1; r < w2; r++){
							//m(g, s, r, t)
							//w1 = s, w2 = t, r = r;
							double prodProb_gsrt = getGrandTripProb(g, w1, r, w2, probs_gtrips) + probs_gsibs[g][r][w2][1];
							coord = pipe_gs->isCoord(instance, w1, r);
							if(coord){
								prodProb_gsrt += probs_coords[g][w1][w2];
							}
							prodProb_gsrt += probs_trips[w1][r][w2] + probs_sibs[r][w2][1] + probs_grands[g][w1][w2] + probs_gchs[g][w2] + probs[w1][w2][0];
							key_a = getKey(g, w1, w2, 0, 0, length);
							key_b1 = getKey(g, w1, r, 0, 0, length);
							key_b2 = getKey(w1, r, w2, 0, 2, length);
							m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gsrt - z);
						}
					}
					else{
						//m(g, t, - s)
						//w1 = s, w2 = t
						double prodProb_gtts = getGrandTripProb(g, w2, w2, w1, probs_gtrips) + probs_gsibs[g][w2][w1][0];
						prodProb_gtts += probs_trips[w2][w2][w1] + probs_sibs[w2][w1][0] + probs_grands[g][w2][w1] + probs_gchs[g][w1] + probs[w1][w2][1];
						key_a = getKey(g, w1, w2, 1, 0, length);
						key_b1 = getKey(w2, w1, w2 - 1, 0, 1, length);
						m += exp(beta[key_b1] + alpha[key_a] + prodProb_gtts - z);

						for(int r = w1 + 1; r < w2; r++){
							//m(g, t, r, s)
							//w1 = s, w2 = t, r = r
							double prodProb_gtrs = getGrandTripProb(g, w2, r, w1, probs_gtrips) + probs_gsibs[g][r][w1][1];
							coord = pipe_gs->isCoord(instance, w2, r);
							if(coord){
								prodProb_gtrs += probs_coords[g][w2][w1];
							}
							prodProb_gtrs += probs_trips[w2][r][w1] + probs_sibs[r][w1][1] + probs_grands[g][w2][w1] + probs_gchs[g][w1] + probs[w1][w2][1];
							key_a = getKey(g, w1, w2, 1, 0, length);
							key_b1 = getKey(g, r, w2, 1, 0, length);
							key_b2 = getKey(w2, w1 ,r, 0, 2, length);
							m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gtrs - z);
						}
					}
				}
				if(w1 == 0 && ph == 0){
					//m(-, 0, - t)
					//w1 = s = 0, w2 = t
					double prodProb_00t = probs_trips[0][0][w2] + probs_sibs[0][w2][0] + probs[0][w2][0];
					key_a = getKey(0, 0, w2, 0, 0, length);
					key_b1 = getKey(0, 1, w2, 1, 1, length);
					m += exp(beta[key_b1] + alpha[key_a] + prodProb_00t - z);

					for(int r = 1; r < w2; r++){
						//m(-, 0, r, t)
						//w1 = s = 0, w2 = t, r = r
						double prodProb_0rt = probs_trips[0][r][w2] + probs_sibs[r][w2][1] + probs[0][w2][0];
						key_a = getKey(0, 0, w2, 0, 0, length);
						key_b1 = getKey(0, 0, r, 0, 0, length);
						key_b2 = getKey(0, r, w2, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_0rt - z);
					}
				}
				if(w2 == end && ph == 1){
					//m(-, n, -, s)
					//w2 = t = n, w1 = s
					double prodProb_nns = probs_trips[end][end][w1] + probs_sibs[end][w1][0] + probs[w1][end][1];
					key_a = getKey(w1, w1, end, 1, 0, length);
					key_b1 = getKey(end, w1, end - 1, 0, 1, length);
					m += exp(beta[key_b1] + alpha[key_a] + prodProb_nns - z);

					for(int r = w1 + 1; r < end; r++){
						//m(-, n, r, s)
						//w2 = t = n, w1 = s, r = r
						double prodProb_nrs = probs_trips[end][r][w1] + probs_sibs[r][w1][1] + probs[w1][end][1];
						key_a = getKey(w1, w1, end, 1, 0, length);
						key_b1 = getKey(end, w1, r, 0, 2, length);
						key_b2 = getKey(r, r, end, 1, 0, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_nrs - z);
					}
				}
				updataExpected(expected, keys, m, size);
				delete[](keys);
			}
		}
	}
	int last = in->readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1; w2 < length; w2++){
			for(int w3 = w2 + 1; w3 < length; w3++){
				int *keys = NULL;
				int size = in->readArray(keys);
				double m = 0.0;
				int key_a, key_b1, key_b2;
				for(int g = 0; g < length; g++){
					if(g >= w1 && g <= w3){
						continue;
					}
					if(w1 == w2){
						//m(g, s, -, t)
						//g = g, w1 = s, w2 = r, w3 = t
						double prodProb_gsst = getGrandTripProb(g, w1, w1, w3, probs_gtrips) + probs_gsibs[g][w2][w3][0];
						prodProb_gsst += probs_trips[w1][w2][w3] + probs_sibs[w2][w3][0] + probs_grands[g][w1][w3] + probs_gchs[g][w3] + probs[w1][w3][0];
						key_a = getKey(g, w1, w3, 0, 0, length);
						key_b1 = getKey(w1, w1 + 1, w3, 1, 1, length);
						m += exp(beta[key_b1] + alpha[key_a] + prodProb_gsst - z);
					}
					else{
						//m(g, s, r, t)
						//g = g, w1 = s, w2 = r, w3 = t
						double prodProb_gsrt = getGrandTripProb(g, w1, w2, w3, probs_gtrips) + probs_gsibs[g][w2][w3][1];
						coord = pipe_gs->isCoord(instance, w1, w2);
						if(coord){
							prodProb_gsrt += probs_coords[g][w1][w3];
						}
						prodProb_gsrt += probs_trips[w1][w2][w3] + probs_sibs[w2][w3][1] + probs_grands[g][w1][w3] + probs_gchs[g][w3] + probs[w1][w3][0];
						key_a = getKey(g, w1, w3, 0, 0, length);
						key_b1 = getKey(g, w1, w2, 0, 0, length);
						key_b2 = getKey(w1, w2, w3, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gsrt - z);
					}
				}
				if(w1 == 0){
					if(w2 == 0){
						//m(-, 0, -, t)
						//w1 = s, w2 = r, w3 = t
						double prodProb_00t = probs_trips[0][0][w3] + probs_sibs[0][w3][0] + probs[0][w3][0];
						key_a = getKey(0, 0, w3, 0, 0, length);
						key_b1 = getKey(0, 1 ,w3, 1, 1, length);
						m += exp(beta[key_b1] + alpha[key_a] + prodProb_00t - z);
					}
					else{
						//m(-, 0, r, t)
						//w1 = s, w2 = r, w3 = t
						double prodProb_0rt = probs_trips[0][w2][w3] + probs_sibs[w2][w3][1] + probs[0][w3][0];
						key_a = getKey(0, 0, w3, 0, 0, length);
						key_b1 = getKey(0, 0, w2, 0, 0, length);
						key_b2 = getKey(0, w2, w3, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_0rt - z);
					}
				}
				updataExpected(expected, keys, m, size);
				delete[](keys);
			}
		}
		for(int w2 = w1; w2 >= 0; w2--){
			for(int w3 = w2 - 1; w3 >= 0; w3--){
				int *keys = NULL;
				int size = in->readArray(keys);
				double m = 0.0;
				int key_a, key_b1, key_b2;
				for(int g = 0; g < length; g++){
					if(g >= w3 && g <= w1){
						continue;
					}
					if(w1 == w2){
						//m(g, t, -, s)
						//g = g, w1 = t, w2 = r, w3 = s
						double prodProb_gtts = getGrandTripProb(g, w1, w2, w3, probs_gtrips) + probs_gsibs[g][w2][w3][0];
						prodProb_gtts += probs_trips[w1][w2][w3] + probs_sibs[w2][w3][0] + probs_grands[g][w1][w3] + probs_gchs[g][w3] + probs[w3][w1][1];
						key_a = getKey(g, w3, w1, 1, 0, length);
						key_b1 = getKey(w1, w3, w1 - 1, 0, 1, length);
						m += exp(beta[key_b1] + alpha[key_a] + prodProb_gtts - z);
					}
					else{
						//m(g, t, r, s)
						//g = g, w1 = t, w2 = r, w3 = s
						double prodProb_gtrs = getGrandTripProb(g, w1, w2, w3, probs_gtrips) + probs_gsibs[g][w2][w3][1];
						coord = pipe_gs->isCoord(instance, w1, w2);
						if(coord){
							prodProb_gtrs += probs_coords[g][w1][w3];
						}
						prodProb_gtrs += probs_trips[w1][w2][w3] + probs_sibs[w2][w3][1] + probs_grands[g][w1][w3] + probs_gchs[g][w3] + probs[w3][w1][1];
						key_a = getKey(g, w3, w1, 1, 0, length);
						key_b1 = getKey(g, w2, w1, 1, 0, length);
						key_b2 = getKey(w1, w3, w2, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gtrs - z);
					}
				}
				if(w1 == end){
					if(w2 == end){
						//m(-, n, -, s)
						//w1 = t, w2 = r, w3 = s
						double prodProb_nns = probs_trips[end][end][w3] + probs_sibs[end][w3][0] + probs[w3][end][1];
						key_a = getKey(w3, w3, end, 1, 0, length);
						key_b1 = getKey(end, w3, end - 1, 0, 1, length);
						m += exp(beta[key_b1] + alpha[key_a] + prodProb_nns - z);
					}
					else{
						//m(-, n, r, s)
						//w1 = t, w2 = r, w3 = s
						double prodProb_nrs = probs_trips[end][w2][w3] + probs_sibs[w2][w3][1] + probs[w3][end][1];
						key_a = getKey(w3, w3, end, 1, 0, length);
						key_b1 = getKey(end, w3, w2, 0, 2, length);
						key_b2 = getKey(w2, w2, end, 1, 0, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_nrs - z);
					}
				}
				updataExpected(expected, keys, m, size);
				delete[](keys);
			}
		}
	}
	last = in->readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = 0; w2 <length; w2++){
			for(int wh = 0; wh < 2; wh++){
				if(w1 != w2){
					int *keys = NULL;
					int size = in->readArray(keys);
					double m = 0.0;
					int key_a, key_b1, key_b2;
					if(wh == 0){
						if(w1 < w2){
							//w1 = s, w2 = t;
							for(int g = 0; g < length; g++){
								if(g >= w1 && g <= w2){
									continue;
								}
								//m(g, s, -, t)
								//g = g, w1 = s, w2 = t
								key_a = getKey(g, w1, w2, 0, 0, length);
								key_b1 = getKey(w1, w1 + 1, w2, 1, 1, length);
								double prodProb_gsst = getGrandTripProb(g, w1, w1, w2, probs_gtrips) + probs_gsibs[g][w1][w2][0];
								prodProb_gsst += probs_trips[w1][w1][w2] + probs_sibs[w1][w2][0] + probs_grands[g][w1][w2] + probs_gchs[g][w2] + probs[w1][w2][0];
								m += exp(beta[key_b1] + alpha[key_a] + prodProb_gsst -z);
							}
							if(w1 == 0){
								//m(-, 0, -, t)
								//w1 = s, w2 = t
								double prodProb_00t = probs_trips[0][0][w2] + probs_sibs[0][w2][0] + probs[0][w2][0];
								key_a = getKey(0, 0, w2, 0, 0, length);
								key_b1 = getKey(0, 1, w2, 1, 1, length);
								m += exp(beta[key_b1] + alpha[key_a] + prodProb_00t - z);
							}
						}
						else{
							//w1 = t, w2 = s
							for(int g = 0; g < length; g++){
								if(g >= w2 && g <= w1){
									continue;
								}
								//m(g, t, - , s)
								//g = g, w1 = t, w2 = s
								key_a = getKey(g, w2, w1, 1, 0, length);
								key_b1 = getKey(w1, w2, w1 - 1, 0, 1, length);
								double prodProb_gtts = getGrandTripProb(g, w1, w1, w2, probs_gtrips) + probs_gsibs[g][w1][w2][0];
								prodProb_gtts += probs_trips[w1][w1][w2] + probs_sibs[w1][w2][0] + probs_grands[g][w1][w2] + probs_gchs[g][w2] + probs[w2][w1][1];
								m += exp(beta[key_b1] + alpha[key_a] + prodProb_gtts - z);
							}
							if(w1 == end){
								//m(-, n, -, s)
								//w1 = t, w2 = s
								double prodProb_nns = probs_trips[end][end][w2] + probs_sibs[end][w2][0] + probs[w2][end][1];
								key_a = getKey(w2, w2, end, 1, 0, length);
								key_b1 = getKey(end, w2, end - 1, 0, 1, length);
								m += exp(beta[key_b1] + alpha[key_a] + prodProb_nns - z);
							}
						}
					}
					else{
						if(w1 < w2){
							//s = s, w1 = r, w2 = t
							for(int s = 0; s < w1; s++){
								for(int g = 0; g < length; g++){
									if(g >= s && g <= w2){
										continue;
									}
									//m(g, s, r, t)
									//g = g, s = s, w1 = r, w2 = t
									double prodProb_gsrt = getGrandTripProb(g, s, w1, w2, probs_gtrips) + probs_gsibs[g][w1][w2][1];
									coord = pipe_gs->isCoord(instance, s, w1);
									if(coord){
										prodProb_gsrt += probs_coords[g][s][w2];
									}
									prodProb_gsrt += probs_trips[s][w1][w2] + probs_sibs[w1][w2][1] + probs_grands[g][s][w2] + probs_gchs[g][w2] + probs[s][w2][0];
									key_a = getKey(g, s, w2, 0, 0, length);
									key_b1 = getKey(g, s, w1, 0, 0, length);
									key_b2 = getKey(s, w1, w2, 0, 2, length);
									m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gsrt - z);
								}
								if(s == 0){
									//m(-, 0, r, t)
									//w1 = r, w2 = t
									double prodProb_0rt = probs_trips[0][w1][w2] + probs_sibs[w1][w2][1] + probs[0][w2][0];
									key_a = getKey(0, 0, w2, 0, 0, length);
									key_b1 = getKey(0, 0, w1, 0, 0, length);
									key_b2 = getKey(0, w1, w2, 0, 2, length);
									m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_0rt -z);
								}
							}
						}
						else{
							//w2 = s, w1 = r, t = t
							for(int t = w1 + 1; t < length; t++){
								for(int g = 0; g < length; g++){
									if(g >= w2 && g <= t){
										continue;
									}
									//m(g, t, r, s)
									//g = g, w1 = r, w2 = s, t = t
									double prodProb_gtrs = getGrandTripProb(g, t, w1, w2, probs_gtrips) + probs_gsibs[g][w1][w2][1];
									coord = pipe_gs->isCoord(instance, t, w1);
									if(coord){
										prodProb_gtrs += probs_coords[g][t][w2];
									}
									prodProb_gtrs += probs_trips[t][w1][w2] + probs_sibs[w1][w2][1] + probs_grands[g][t][w2] + probs_gchs[g][w2] + probs[w2][t][1];
									key_a = getKey(g, w2, t, 1, 0, length);
									key_b1 = getKey(g, w1, t, 1, 0, length);
									key_b2 = getKey(t, w2, w1, 0, 2, length);
									m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gtrs - z);
								}
								if(t == end){
									//m(-, n, r, s)
									//w1 = r, w2 = s
									double prodProb_nrs = probs_trips[end][w1][w2] + probs_sibs[w1][w2][1] + probs[w2][end][1];
									key_a = getKey(w2, w2, end, 1, 0, length);
									key_b1 = getKey(end, w2, w1, 0, 2, length);
									key_b2 = getKey(w1, w1, end, 1, 0, length);
									m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_nrs -z);
								}
							}
						}
					}
					updataExpected(expected, keys, m, size);
					delete[](keys);
				}
			}
		}
	}
	last = in->readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1 + 1; w2 < length; w2++){
			for(int w3 = w1 + 1; w3 < length; w3++){
				if(w3 == w2){
					continue;
				}

				int *keys = NULL;
				int size = in->readArray(keys);
				double m = 0.0;
				int key_a, key_b1, key_b2;
				if(w3 < w2){
					//m(g, t, -, s)
					//w1 = g, w2 = t, w3 = s
					double prodProb_gtts = getGrandTripProb(w1, w2, w2, w3, probs_gtrips) + probs_gsibs[w1][w2][w3][0];
					prodProb_gtts += probs_trips[w2][w2][w3] + probs_sibs[w2][w3][0] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w3][w2][1];
					key_a = getKey(w1, w3, w2, 1, 0, length);
					key_b1 = getKey(w2, w3, w2 - 1, 0, 1, length);
					m += exp(beta[key_b1] + alpha[key_a] + prodProb_gtts - z);

					for(int r = w3 + 1; r < w2; r++){
						//m(g, t, r, s)
						//w1 = g, w2 = t, w3 = s, r = r
						double prodProb_gtrs = getGrandTripProb(w1, w2, r, w3, probs_gtrips) + probs_gsibs[w1][r][w3][1];
						coord = pipe_gs->isCoord(instance, w2, r);
						if(coord){
							prodProb_gtrs += probs_coords[w1][w2][w3];
						}
						prodProb_gtrs += probs_trips[w2][r][w3] + probs_sibs[r][w3][1] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w3][w2][1];
						key_a = getKey(w1, w3, w2, 1, 0, length);
						key_b1 = getKey(w1, r, w2, 1, 0, length);
						key_b2 = getKey(w2, w3, r, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gtrs - z);
					}
				}
				else{
					//m(g, s, -, t)
					//w1 = g, w2 = s, w3 = t
					double prodProb_gsst = getGrandTripProb(w1, w2, w2, w3, probs_gtrips) + probs_gsibs[w1][w2][w3][0];
					prodProb_gsst += probs_trips[w2][w2][w3] + probs_sibs[w2][w3][0] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w2][w3][0];
					key_a = getKey(w1, w2, w3, 0, 0, length);
					key_b1 = getKey(w2, w2 + 1, w3, 1, 1, length);
					m += exp(beta[key_b1] + alpha[key_a] + prodProb_gsst - z);

					for(int r = w2 + 1; r < w3; r++){
						//m(g, s, r, t)
						//w1 = g, w2 = s, w3 = t, r = r
						double prodProb_gsrt = getGrandTripProb(w1, w2, r, w3, probs_gtrips) + probs_gsibs[w1][r][w3][1];
						coord = pipe_gs->isCoord(instance, w2, r);
						if(coord){
							prodProb_gsrt += probs_coords[w1][w2][w3];
						}
						prodProb_gsrt += probs_trips[w2][r][w3] + probs_sibs[r][w3][1] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w2][w3][0];
						key_a = getKey(w1, w2, w3, 0, 0, length);
						key_b1 = getKey(w1, w2, r, 0, 0, length);
						key_b2 = getKey(w2, r, w3, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gsrt - z);
					}
				}
				updataExpected(expected, keys, m, size);
				delete[](keys);
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w1 - 1; w3 >= 0; w3--){
				if(w2 == w3){
					continue;
				}

				int *keys = NULL;
				int size = in->readArray(keys);
				double m = 0.0;
				int key_a, key_b1, key_b2;
				if(w3 < w2){
					//m(g, t, -, s)
					//w1 = g, w2 = t, w3 = s
					double prodProb_gtts = getGrandTripProb(w1, w2, w2, w3, probs_gtrips) + probs_gsibs[w1][w2][w3][0];
					prodProb_gtts += probs_trips[w2][w2][w3] + probs_sibs[w2][w3][0] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w3][w2][1];
					key_a = getKey(w1, w3, w2, 1, 0, length);
					key_b1 = getKey(w2, w3, w2 - 1, 0, 1, length);
					m += exp(beta[key_b1] + alpha[key_a] + prodProb_gtts - z);

					for(int r = w3 + 1; r < w2; r++){
						//m(g, t, r, s)
						//w1 = g, w2 = t, w3 = s, r = r
						double prodProb_gtrs = getGrandTripProb(w1, w2, r, w3, probs_gtrips) + probs_gsibs[w1][r][w3][1];
						coord = pipe_gs->isCoord(instance, w2, r);
						if(coord){
							prodProb_gtrs += probs_coords[w1][w2][w3];
						}
						prodProb_gtrs += probs_trips[w2][r][w3] + probs_sibs[r][w3][1] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w3][w2][1];
						key_a = getKey(w1, w3, w2, 1, 0, length);
						key_b1 = getKey(w1, r, w2, 1, 0, length);
						key_b2 = getKey(w2, w3, r, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gtrs - z);
					}
				}
				else{
					//m(g, s, -, t)
					//w1 = g, w2 = s, w3 = t
					double prodProb_gsst = getGrandTripProb(w1, w2, w2, w3, probs_gtrips) + probs_gsibs[w1][w2][w3][0];
					prodProb_gsst += probs_trips[w2][w2][w3] + probs_sibs[w2][w3][0] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w2][w3][0];
					key_a = getKey(w1, w2, w3, 0, 0, length);
					key_b1 = getKey(w2, w2 + 1, w3, 1, 1, length);
					m += exp(beta[key_b1] + alpha[key_a] + prodProb_gsst - z);

					for(int r = w2 + 1; r < w3; r++){
						//m(g, s, r, t)
						//w1 = g, w2 = s, w3 = t, r = r
						double prodProb_gsrt = getGrandTripProb(w1, w2, r, w3, probs_gtrips) + probs_gsibs[w1][r][w3][1];
						coord = pipe_gs->isCoord(instance, w2, r);
						if(coord){
							prodProb_gsrt += probs_coords[w1][w2][w3];
						}
						prodProb_gsrt += probs_trips[w2][r][w3] + probs_sibs[r][w3][1] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w2][w3][0];
						key_a = getKey(w1, w2, w3, 0, 0, length);
						key_b1 = getKey(w1, w2, r, 0, 0, length);
						key_b2 = getKey(w2, r, w3, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gsrt - z);
					}
				}
				updataExpected(expected, keys, m, size);
				delete[](keys);
			}
		}
	}
	last = in->readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1 + 1; w2 < length; w2++){
			int *keys = NULL;
			int size = in->readArray(keys);
			double m = 0.0;
			int key_a, key_b1, key_b2;
			for(int w3 = w1 + 1; w3 < length; w3++){
				if(w3 == w2){
					continue;
				}

				if(w3 < w2){
					//m(g, s, -, t)
					//w1 = g, w2 = t, w3 = s
					double prodProb_gsst = getGrandTripProb(w1, w3, w3, w2, probs_gtrips) + probs_gsibs[w1][w3][w2][0];
					prodProb_gsst += probs_trips[w3][w3][w2] + probs_sibs[w3][w2][0] + probs_grands[w1][w3][w2] + probs_gchs[w1][w2] + probs[w3][w2][0];
					key_a = getKey(w1, w3, w2, 0, 0, length);
					key_b1 = getKey(w3, w3 + 1, w2, 1, 1, length);
					m += exp(beta[key_b1] + alpha[key_a] + prodProb_gsst - z);

					for(int r = w3 + 1; r < w2; r++){
						//m(g, s, r, t)
						//w1 = g, w2 = t, w3 = s, r = r
						double prodProb_gsrt = getGrandTripProb(w1, w3, r, w2, probs_gtrips) + probs_gsibs[w1][r][w2][1];
						coord = pipe_gs->isCoord(instance, w3, r);
						if(coord){
							prodProb_gsrt += probs_coords[w1][w3][w2];
						}
						prodProb_gsrt += probs_trips[w3][r][w2] + probs_sibs[r][w2][1] + probs_grands[w1][w3][w2] + probs_gchs[w1][w2] + probs[w3][w2][0];
						key_a = getKey(w1, w3, w2, 0, 0, length);
						key_b1 = getKey(w1, w3, r, 0, 0, length);
						key_b2 = getKey(w3, r, w2, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gsrt - z);
					}
				}
				else{
					//m(g, t, -, s)
					//w1 = g, w2 = s, w3 = t
					double prodProb_gtts = getGrandTripProb(w1, w3, w3, w2, probs_gtrips) + probs_gsibs[w1][w3][w2][0];
					prodProb_gtts += probs_trips[w3][w3][w2] + probs_sibs[w3][w2][0] + probs_grands[w1][w3][w2] + probs_gchs[w1][w2] + probs[w2][w3][1];
					key_a = getKey(w1, w2, w3, 1, 0, length);
					key_b1 = getKey(w3, w2, w3 - 1, 0, 1, length);
					m += exp(beta[key_b1] + alpha[key_a] + prodProb_gtts - z);

					for(int r = w2 + 1; r < w3; r++){
						//m(g, t, r, s)
						//w1 = g, w2 = s, w3 = t, r = r
						double prodProb_gtrs = getGrandTripProb(w1, w3, r, w2, probs_gtrips) + probs_gsibs[w1][r][w2][1];
						coord = pipe_gs->isCoord(instance, w3, r);
						if(coord){
							prodProb_gtrs += probs_coords[w1][w3][w2];
						}
						prodProb_gtrs += probs_trips[w3][r][w2] + probs_sibs[r][w2][1] + probs_grands[w1][w3][w2] + probs_gchs[w1][w2] + probs[w2][w3][1];
						key_a = getKey(w1, w2, w3, 1, 0, length);
						key_b1 = getKey(w1, r, w3, 1, 0, length);
						key_b2 = getKey(w3, w2, r, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gtrs - z);
					}
				}
			}
			updataExpected(expected, keys, m, size);
			delete[](keys);
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			int *keys = NULL;
			int size = in->readArray(keys);
			double m = 0.0;
			int key_a, key_b1, key_b2;
			for(int w3 = w1 - 1; w3 >= 0; w3--){
				if(w2 == w3){
					continue;
				}

				if(w3 < w2){
					//m(g, s, -, t)
					//w1 = g, w2 = t, w3 = s
					double prodProb_gsst = getGrandTripProb(w1, w3, w3, w2, probs_gtrips) + probs_gsibs[w1][w3][w2][0];
					prodProb_gsst += probs_trips[w3][w3][w2] + probs_sibs[w3][w2][0] + probs_grands[w1][w3][w2] + probs_gchs[w1][w2] + probs[w3][w2][0];
					key_a = getKey(w1, w3, w2, 0, 0, length);
					key_b1 = getKey(w3, w3 + 1, w2, 1, 1, length);
					m += exp(beta[key_b1] + alpha[key_a] + prodProb_gsst - z);

					for(int r = w3 + 1; r < w2; r++){
						//m(g, s, r, t)
						//w1 = g, w2 = t, w3 = s, r = r
						double prodProb_gsrt = getGrandTripProb(w1, w3, r, w2, probs_gtrips) + probs_gsibs[w1][r][w2][1];
						coord = pipe_gs->isCoord(instance, w3, r);
						if(coord){
							prodProb_gsrt += probs_coords[w1][w3][w2];
						}
						prodProb_gsrt += probs_trips[w3][r][w2] + probs_sibs[r][w2][1] + probs_grands[w1][w3][w2] + probs_gchs[w1][w2] + probs[w3][w2][0];
						key_a = getKey(w1, w3, w2, 0, 0, length);
						key_b1 = getKey(w1, w3, r, 0, 0, length);
						key_b2 = getKey(w3, r, w2, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gsrt - z);
					}
				}
				else{
					//m(g, t, -, s)
					//w1 = g, w2 = s, w3 = t
					double prodProb_gtts = getGrandTripProb(w1, w3, w3, w2, probs_gtrips) + probs_gsibs[w1][w3][w2][0];
					prodProb_gtts += probs_trips[w3][w3][w2] + probs_sibs[w3][w2][0] + probs_grands[w1][w3][w2] + probs_gchs[w1][w2] + probs[w2][w3][1];
					key_a = getKey(w1, w2, w3, 1, 0, length);
					key_b1 = getKey(w3, w2, w3 - 1, 0, 1, length);
					m += exp(beta[key_b1] + alpha[key_a] + prodProb_gtts - z);

					for(int r = w2 + 1; r < w3; r++){
						//m(g, t, r, s)
						//w1 = g, w2 = s, w3 = t, r = r
						double prodProb_gtrs = getGrandTripProb(w1, w3, r, w2, probs_gtrips) + probs_gsibs[w1][r][w2][1];
						coord = pipe_gs->isCoord(instance, w3, r);
						if(coord){
							prodProb_gtrs += probs_coords[w1][w3][w2];
						}
						prodProb_gtrs += probs_trips[w3][r][w2] + probs_sibs[r][w2][1] + probs_grands[w1][w3][w2] + probs_gchs[w1][w2] + probs[w2][w3][1];
						key_a = getKey(w1, w2, w3, 1, 0, length);
						key_b1 = getKey(w1, r, w3, 1, 0, length);
						key_b2 = getKey(w3, w2, r, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gtrs - z);
					}
				}
			}
			updataExpected(expected, keys, m, size);
			delete[](keys);
		}
	}
	last = in->readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1 + 1; w2 < length; w2++){
			for(int w3 = w2; w3 < length; w3++){
				for(int w4 = w3 + 1; w4 < length; w4++){
					int key_a, key_b1, key_b2;
					int *keys = NULL;
					int size = in->readArray(keys);
					double m = 0.0;
					if(w2 == w3){
						//m(g, s, s, t)
						//g = w1, s = w2 = r = w3, t = w4
						double prodProb_gsst = getGrandTripProb(w1, w2, w3, w4, probs_gtrips) + probs_gsibs[w1][w2][w4][0];
						prodProb_gsst += probs_trips[w2][w3][w4] + probs_sibs[w2][w4][0] + probs_grands[w1][w2][w4] + probs_gchs[w1][w4] + probs[w2][w4][0];
						key_a = getKey(w1, w2, w4, 0, 0, length);
						key_b1 = getKey(w2, w2 + 1, w4, 1, 1, length);
						m = exp(beta[key_b1] + alpha[key_a] + prodProb_gsst - z);
					}
					else{
						//m(g, s, r, t)
						//g = w1, s = w2, r = w3, t = w4;
						double prodProb_gsrt = getGrandTripProb(w1, w2, w3, w4, probs_gtrips) + probs_gsibs[w1][w3][w4][1];
						coord = pipe_gs->isCoord(instance, w2, w3);
						if(coord){
							prodProb_gsrt += probs_coords[w1][w2][w4];
						}
						prodProb_gsrt += probs_trips[w2][w3][w4] + probs_sibs[w3][w4][1] + probs_grands[w1][w2][w4] + probs_gchs[w1][w4] + probs[w2][w4][0];
						key_a = getKey(w1, w2, w4, 0, 0, length);
						key_b1 = getKey(w1, w2, w3, 0, 0, length);
						key_b2 = getKey(w2, w3, w4, 0, 2, length);
						m = exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gsrt - z);
					}
					updataExpected(expected, keys, m, size);
					delete[](keys);
				}
			}
			for(int w3 = w2; w3 > w1; w3--){
				for(int w4 = w3 - 1; w4 > w1; w4--){
					int key_a, key_b1, key_b2;
					int *keys = NULL;
					int size = in->readArray(keys);
					double m = 0.0;
					if(w2 == w3){
						//m(g, t, t, s)
						//g = w1, t = w2 = r = w3, s = w4;
						double prodProb_gtts = getGrandTripProb(w1, w2, w3, w4, probs_gtrips) + probs_gsibs[w1][w2][w4][0];
						prodProb_gtts += probs_trips[w2][w3][w4] + probs_sibs[w2][w4][0] + probs_grands[w1][w2][w4] + probs_gchs[w1][w4] + probs[w4][w2][1];
						key_a = getKey(w1, w4, w2, 1, 0, length);
						key_b1 = getKey(w2, w4, w2 - 1, 0, 1, length);
						m = exp(beta[key_b1] + alpha[key_a] + prodProb_gtts - z);
					}
					else{
						//m(g, t, r, s)
						//g = w1, t = w2, r = w3, s = w4;
						double prodProb_gtrs = getGrandTripProb(w1, w2, w3, w4, probs_gtrips) + probs_gsibs[w1][w3][w4][1];
						coord = pipe_gs->isCoord(instance, w2, w3);
						if(coord){
							prodProb_gtrs += probs_coords[w1][w2][w4];
						}
						prodProb_gtrs += probs_trips[w2][w3][w4] + probs_sibs[w3][w4][1] + probs_grands[w1][w2][w4] + probs_gchs[w1][w4] + probs[w4][w2][1];
						key_a = getKey(w1, w4, w2, 1, 0, length);
						key_b1 = getKey(w1, w3, w2, 1, 0, length);
						key_b2 = getKey(w2, w4, w3, 0, 2, length);
						m = exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gtrs - z);
					}
					updataExpected(expected, keys, m, size);
					delete[](keys);
				}
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w2; w3 < w1; w3++){
				for(int w4 = w3 + 1; w4 < w1; w4++){
					int key_a, key_b1, key_b2;
					int *keys = NULL;
					int size = in->readArray(keys);
					double m = 0.0;
					if(w2 == w3){
						//m(g, s, s, t)
						//g = w1, s = w2 = r = w3, t = w4
						double prodProb_gsst = getGrandTripProb(w1, w2, w3, w4, probs_gtrips) + probs_gsibs[w1][w2][w4][0];
						prodProb_gsst += probs_trips[w2][w3][w4] + probs_sibs[w2][w4][0] + probs_grands[w1][w2][w4] + probs_gchs[w1][w4] + probs[w2][w4][0];
						key_a = getKey(w1, w2, w4, 0, 0, length);
						key_b1 = getKey(w2, w2 + 1, w4, 1, 1, length);
						m = exp(beta[key_b1] + alpha[key_a] + prodProb_gsst - z);
					}
					else{
						//m(g, s, r, t)
						//g = w1, s = w2, r = w3, t = w4;
						double prodProb_gsrt = getGrandTripProb(w1, w2, w3, w4, probs_gtrips) + probs_gsibs[w1][w3][w4][1];
						coord = pipe_gs->isCoord(instance, w2, w3);
						if(coord){
							prodProb_gsrt += probs_coords[w1][w2][w4];
						}
						prodProb_gsrt += probs_trips[w2][w3][w4] + probs_sibs[w3][w4][1] + probs_grands[w1][w2][w4] + probs_gchs[w1][w4] + probs[w2][w4][0];
						key_a = getKey(w1, w2, w4, 0, 0, length);
						key_b1 = getKey(w1, w2, w3, 0, 0, length);
						key_b2 = getKey(w2, w3, w4, 0, 2, length);
						m = exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gsrt - z);
					}
					updataExpected(expected, keys, m, size);
					delete[](keys);
				}
			}
			for(int w3 = w2; w3 >= 0; w3--){
				for(int w4 = w3 -1; w4 >= 0; w4--){
					int key_a, key_b1, key_b2;
					int *keys = NULL;
					int size = in->readArray(keys);
					double m = 0.0;
					if(w2 == w3){
						//m(g, t, t, s)
						//g = w1, t = w2 = r = w3, s = w4;
						double prodProb_gtts = getGrandTripProb(w1, w2, w3, w4, probs_gtrips) + probs_gsibs[w1][w2][w4][0];
						prodProb_gtts += probs_trips[w2][w3][w4] + probs_sibs[w2][w4][0] + probs_grands[w1][w2][w4] + probs_gchs[w1][w4] + probs[w4][w2][1];
						key_a = getKey(w1, w4, w2, 1, 0, length);
						key_b1 = getKey(w2, w4, w2 - 1, 0, 1, length);
						m = exp(beta[key_b1] + alpha[key_a] + prodProb_gtts - z);
					}
					else{
						//m(g, t, r, s)
						//g = w1, t = w2, r = w3, s = w4;
						double prodProb_gtrs = getGrandTripProb(w1, w2, w3, w4, probs_gtrips) + probs_gsibs[w1][w3][w4][1];
						coord = pipe_gs->isCoord(instance, w2, w3);
						if(coord){
							prodProb_gtrs += probs_coords[w1][w2][w4];
						}
						prodProb_gtrs += probs_trips[w2][w3][w4] + probs_sibs[w3][w4][1] + probs_grands[w1][w2][w4] + probs_gchs[w1][w4] + probs[w4][w2][1];
						key_a = getKey(w1, w4, w2, 1, 0, length);
						key_b1 = getKey(w1, w3, w2, 1, 0, length);
						key_b2 = getKey(w2, w4, w3, 0, 2, length);
						m = exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gtrs - z);
					}
					updataExpected(expected, keys, m, size);
					delete[](keys);
				}
			}
		}
	}
	last = in->readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1 + 1; w2 < length; w2++){
			for(int w3 = w1 + 1; w3 < length; w3++){
				for(int wh = 0; wh < 2; wh++){
					int key_a, key_b1, key_b2;
					if(w2 != w3){
						int *keys = NULL;
						int size = in->readArray(keys);
						double m = 0.0;
						if(wh == 0){
							if(w2 < w3){
								//m(g, s, s, t)
								//g = w1, s = r = w2, t = w3
								double prodProb_gsst = getGrandTripProb(w1, w2, w2, w3, probs_gtrips) + probs_gsibs[w1][w2][w3][0];
								prodProb_gsst += probs_trips[w2][w2][w3] + probs_sibs[w2][w3][0] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w2][w3][0];
								key_a = getKey(w1, w2, w3, 0, 0, length);
								key_b1 = getKey(w2, w2 + 1, w3, 1, 1, length);
								m += exp(beta[key_b1] + alpha[key_a] + prodProb_gsst - z);
							}
							else{
								//m(g, t, t, s)
								//g = w1, t = w2 = r, s = w3
								double prodProb_gtts = getGrandTripProb(w1, w2, w2, w3, probs_gtrips) + probs_gsibs[w1][w2][w3][0];
								prodProb_gtts += probs_trips[w2][w2][w3] + probs_sibs[w2][w3][0] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w3][w2][1];
								key_a = getKey(w1, w3, w2, 1, 0, length);
								key_b1 = getKey(w2, w3, w2 - 1, 0, 1, length);
								m += exp(beta[key_b1] + alpha[key_a] + prodProb_gtts - z);
							}
						}
						else{
							if(w2 < w3){
								for(int s = w1 + 1; s < w2; s++){
									//m(g, s, r, t)
									//g = w1, s = s, r = w2, t = w3
									double prodProb_gsrt = getGrandTripProb(w1, s, w2, w3, probs_gtrips) + probs_gsibs[w1][w2][w3][1];
									coord = pipe_gs->isCoord(instance, s, w2);
									if(coord){
										prodProb_gsrt += probs_coords[w1][s][w3];
									}
									prodProb_gsrt += probs_trips[s][w2][w3] + probs_sibs[w2][w3][1] + probs_grands[w1][s][w3] + probs_gchs[w1][w3] + probs[s][w3][0];
									key_a = getKey(w1, s, w3, 0, 0, length);
									key_b1 = getKey(w1, s, w2, 0, 0, length);
									key_b2 = getKey(s, w2, w3, 0, 2, length);
									m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gsrt - z);
								}
							}
							else{
								for(int t = w2 + 1; t < length; t++){
									//m(g, t, r, s)
									//g = w1, t = t, r = w2, s = w3
									double prodProb_gtrs = getGrandTripProb(w1, t, w2, w3, probs_gtrips) + probs_gsibs[w1][w2][w3][1];
									coord = pipe_gs->isCoord(instance, t, w2);
									if(coord){
										prodProb_gtrs += probs_coords[w1][t][w3];
									}
									prodProb_gtrs += probs_trips[t][w2][w3] + probs_sibs[w2][w3][1] + probs_grands[w1][t][w3] + probs_gchs[w1][w3] + probs[w3][t][1];
									key_a = getKey(w1, w3, t, 1, 0, length);
									key_b1 = getKey(w1, w2, t, 1, 0, length);
									key_b2 = getKey(t, w3, w2, 0, 2, length);
									m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gtrs - z);
								}
							}
						}
						updataExpected(expected, keys, m, size);
						delete[](keys);
					}
				}
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w1 - 1; w3 >= 0; w3--){
				for(int wh = 0; wh < 2; wh++){
					int key_a, key_b1, key_b2;
					if(w2 != w3){
						int *keys = NULL;
						int size = in->readArray(keys);
						double m = 0.0;
						if(wh == 0){
							if(w2 < w3){
								//m(g, s, s, t)
								//g = w1, s = r = w2, t = w3
								double prodProb_gsst = getGrandTripProb(w1, w2, w2, w3, probs_gtrips) + probs_gsibs[w1][w2][w3][0];
								prodProb_gsst += probs_trips[w2][w2][w3] + probs_sibs[w2][w3][0] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w2][w3][0];
								key_a = getKey(w1, w2, w3, 0, 0, length);
								key_b1 = getKey(w2, w2 + 1, w3, 1, 1, length);
								m += exp(beta[key_b1] + alpha[key_a] + prodProb_gsst - z);
							}
							else{
								//m(g, t, t, s)
								//g = w1, t = w2 = r, s = w3
								double prodProb_gtts = getGrandTripProb(w1, w2, w2, w3, probs_gtrips) + probs_gsibs[w1][w2][w3][0];
								prodProb_gtts += probs_trips[w2][w2][w3] + probs_sibs[w2][w3][0] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w3][w2][1];
								key_a = getKey(w1, w3, w2, 1, 0, length);
								key_b1 = getKey(w2, w3, w2 - 1, 0, 1, length);
								m += exp(beta[key_b1] + alpha[key_a] + prodProb_gtts - z);
							}
						}
						else{
							if(w2 < w3){
								for(int s = 0; s < w2; s++){
									//m(g, s, r, t)
									//g = w1, s = s, r = w2, t = w3
									double prodProb_gsrt = getGrandTripProb(w1, s, w2, w3, probs_gtrips) + probs_gsibs[w1][w2][w3][1];
									coord = pipe_gs->isCoord(instance, s, w2);
									if(coord){
										prodProb_gsrt += probs_coords[w1][s][w3];
									}
									prodProb_gsrt += probs_trips[s][w2][w3] + probs_sibs[w2][w3][1] + probs_grands[w1][s][w3] + probs_gchs[w1][w3] + probs[s][w3][0];
									key_a = getKey(w1, s, w3, 0, 0, length);
									key_b1 = getKey(w1, s, w2, 0, 0, length);
									key_b2 = getKey(s, w2, w3, 0, 2, length);
									m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gsrt - z);
								}
							}
							else{
								for(int t = w2 + 1; t < w1; t++){
									//m(g, t, r, s)
									//g = w1, t = t, r = w2, s = w3
									double prodProb_gtrs = getGrandTripProb(w1, t, w2, w3, probs_gtrips) + probs_gsibs[w1][w2][w3][1];
									coord = pipe_gs->isCoord(instance, t, w2);
									if(coord){
										prodProb_gtrs += probs_coords[w1][t][w3];
									}
									prodProb_gtrs += probs_trips[t][w2][w3] + probs_sibs[w2][w3][1] + probs_grands[w1][t][w3] + probs_gchs[w1][w3] + probs[w3][t][1];
									key_a = getKey(w1, w3, t, 1, 0, length);
									key_b1 = getKey(w1, w2, t, 1, 0, length);
									key_b2 = getKey(t, w3, w2, 0, 2, length);
									m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gtrs - z);
								}
							}
						}
						updataExpected(expected, keys, m, size);
						delete[](keys);
					}
				}
			}
		}
	}
	last = in->readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	for(int w1 = 0; w1 < length; w1++){
		for(int w2 = w1 + 1; w2 < length; w2++){
			for(int w3 = w2 + 1; w3 < length; w3++){
				int *keys = NULL;
				int size = in->readArray(keys);
				if(size == 0){
					delete[](keys);
					continue;
				}
				double m = 0.0;
				int key_a, key_b1, key_b2;
				for(int r = w2 + 1; r < w3; r++){
					//m(g, s, r, t)
					//g = w1, s = w2, r = r, t = w3
					coord = pipe_gs->isCoord(instance, w2, r);
					if(coord){
						double prodProb_gsrt = getGrandTripProb(w1, w2, r, w3, probs_gtrips) + probs_gsibs[w1][r][w3][1];
						prodProb_gsrt += probs_coords[w1][w2][w3];
						prodProb_gsrt += probs_trips[w2][r][w3] + probs_sibs[r][w3][1] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w2][w3][0];
						key_a = getKey(w1, w2, w3, 0, 0, length);
						key_b1 = getKey(w1, w2, r, 0, 0, length);
						key_b2 = getKey(w2, r, w3, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gsrt - z);
					}
				}
				updataExpected(expected, keys, m, size);
				delete[](keys);
			}

			for(int w3 = w2 - 1; w3 > w1; w3--){
				int *keys = NULL;
				int size = in->readArray(keys);
				if(size == 0){
					delete[](keys);
					continue;
				}
				double m = 0.0;
				int key_a, key_b1, key_b2;
				for(int r = w3 + 1; r < w2; r++){
					//m(g, t, r, s)
					//g = w1, s = w3, r = r, t = w2
					coord = pipe_gs->isCoord(instance, w2, r);
					if(coord){
						double prodProb_gtrs = getGrandTripProb(w1, w2, r, w3, probs_gtrips) + probs_gsibs[w1][r][w3][1];
						prodProb_gtrs += probs_coords[w1][w2][w3];
						prodProb_gtrs += probs_trips[w2][r][w3] + probs_sibs[r][w3][1] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w3][w2][1];
						key_a = getKey(w1, w3, w2, 1, 0, length);
						key_b1 = getKey(w1, r, w2, 1, 0, length);
						key_b2 = getKey(w2, w3, r, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gtrs - z);
					}
				}
				updataExpected(expected, keys, m, size);
				delete[](keys);
			}
		}

		for(int w2 = w1 - 1; w2 >= 0; w2--){
			for(int w3 = w2 + 1; w3 < w1; w3++){
				int *keys = NULL;
				int size = in->readArray(keys);
				if(size == 0){
					delete[](keys);
					continue;
				}
				double m = 0.0;
				int key_a, key_b1, key_b2;
				for(int r = w2 + 1; r < w3; r++){
					//m(g, s, r, t)
					//g = w1, s = w2, r = r, t = w3
					coord = pipe_gs->isCoord(instance, w2, r);
					if(coord){
						double prodProb_gsrt = getGrandTripProb(w1, w2, r, w3, probs_gtrips) + probs_gsibs[w1][r][w3][1];
						prodProb_gsrt += probs_coords[w1][w2][w3];
						prodProb_gsrt += probs_trips[w2][r][w3] + probs_sibs[r][w3][1] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w2][w3][0];
						key_a = getKey(w1, w2, w3, 0, 0, length);
						key_b1 = getKey(w1, w2, r, 0, 0, length);
						key_b2 = getKey(w2, r, w3, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gsrt - z);
					}
				}
				updataExpected(expected, keys, m, size);
				delete[](keys);
			}

			for(int w3 = w2 - 1; w3 >= 0; w3--){
				int *keys = NULL;
				int size = in->readArray(keys);
				if(size == 0){
					delete[](keys);
					continue;
				}
				double m = 0.0;
				int key_a, key_b1, key_b2;
				for(int r = w3 + 1; r < w2; r++){
					//m(g, t, r, s)
					//g = w1, s = w3, r = r, t = w2
					coord = pipe_gs->isCoord(instance, w2, r);
					if(coord){
						double prodProb_gtrs = getGrandTripProb(w1, w2, r, w3, probs_gtrips) + probs_gsibs[w1][r][w3][1];
						prodProb_gtrs += probs_coords[w1][w2][w3];
						prodProb_gtrs += probs_trips[w2][r][w3] + probs_sibs[r][w3][1] + probs_grands[w1][w2][w3] + probs_gchs[w1][w3] + probs[w3][w2][1];
						key_a = getKey(w1, w3, w2, 1, 0, length);
						key_b1 = getKey(w1, r, w2, 1, 0, length);
						key_b2 = getKey(w2, w3, r, 0, 2, length);
						m += exp(beta[key_b1] + beta[key_b2] + alpha[key_a] + prodProb_gtrs - z);
					}
				}
				updataExpected(expected, keys, m, size);
				delete[](keys);
			}
		}
	}
	last = in->readInt();
	if(last != -3){
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	int *keys = NULL;
	int size = in->readArray(keys);
	for(int i = 0; i < size; i++){
		int j = keys[i];
		expected[j] -= 1.0;
	}
	
	delete[](keys);
	last = in->readInt();
	if (last != -4) {
		cout<<"Error reading file."<<endl;
		exit(0);
	}

	DependencyInstance* inst = new DependencyInstance();
	inst->readObject(*in);

	last = in->readInt();
	if (last != -1) {
		cout<<"Error reading file."<<endl;
		exit(0);
	}
	delete(inst);
}

double DependencyEncoder3OGSibling::gradient(long double *expected, int length){
	long offset = in->objTell();
	DependencyInstance *inst = ((DependencyPipe3OGSibling*)(pipe))->readInstance(*in, length, probs, probs_trips, probs_sibs, probs_grands, probs_gchs, probs_gtrips, probs_gsibs, probs_coords, nt_probs, param);
	if(0 != (in->objSeek(offset))){
		cout<<"error on fseek of trainforset!"<<endl;
		exit(0);
	}

	double obj = 0.0;
	double *beta = new double[length * length * length * 2 * 3];
	double *alpha = new double[length * length * length * 2 * 3];

	double z = getZ(length, beta, inst);

	inside_outside(length, beta, alpha, inst);

	obj = z - param->getScore(inst->fv);

	getExpected(expected, beta, alpha, z, length, inst);

	delete(inst);
	delete[](beta);
	delete[](alpha);

	return obj;
}
